package com.shawn.jetpackstady.room;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import androidx.annotation.NonNull;
import androidx.room.Database;
import androidx.room.DatabaseConfiguration;
import androidx.room.InvalidationTracker;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.sqlite.db.SupportSQLiteOpenHelper;

import com.shawn.jetpackstady.AppContext;
import com.shawn.jetpackstady.room.bean.User;

/**
 * 数据持有者
 * 满足条件：
 * 1.必须继承RoomDatabase
 * 2.至少包含一个带@Dao注释的类的抽象方法
 * 3.entities 参数中包含数据库关联的实体列表
 * 4.初始化实例耗费时间比较长，需要用单例来初始化一个实例
 */
@Database(entities = {User.class}, version = 2)
public abstract class AppDataBase extends RoomDatabase {
    public abstract UserDao getUserDao();

    // 数据库名
    private static final String DB_NAME = "room_db";

    // 静态内部类
    private static class Holder {
        private volatile static AppDataBase appDataBase = null;
        private static Executor executor = Executors.newSingleThreadExecutor();

        static AppDataBase getInstance(Context context) {
            if (appDataBase == null) {
                synchronized (AppDataBase.class) {
                    if (appDataBase == null) {
                        appDataBase = buildDatabase(context);
                    }
                }
            }
            return appDataBase;
        }

        private static AppDataBase buildDatabase(Context context) {
            return Room.databaseBuilder(context, AppDataBase.class, DB_NAME)
                    .addCallback(new RoomDatabase.Callback() {
                        @Override
                        public void onCreate(@NonNull SupportSQLiteDatabase db) {
                            super.onCreate(db);
                            // 第一次创建数据库会回调此方法，可以做初始化数据之类的操作
                            Log.e("shawn", "room_db 数据库第一次创建成功！");
                            // 初始化表中数据
                            executeAssetsSQL(db, "userjson");
                        }

                        @Override
                        public void onOpen(@NonNull SupportSQLiteDatabase db) {
                            super.onOpen(db);
                            Log.e("shawn", "room_db 数据库 onOpen！");
                        }


                    }).addMigrations(new Migration(1, 2) {
                        @Override
                        public void migrate(@NonNull SupportSQLiteDatabase database) {
                            Log.e("shawn", "room_db 数据库升级！");
                            // 升级数据库从版本1升到版本2
                            // 需要修改类名注解处的Version为endVersion，这里对应的就是2
                            // 初始化表中数据
                            executeAssetsSQL(database, "userjson");
                        }
                    })
                    .fallbackToDestructiveMigration()//升级：当未匹配到版本的时候会直接删除表然后重新创建
                    .fallbackToDestructiveMigrationOnDowngrade()//降级:当未匹配到版本的时候就会直接删除表然后重新创建
                    .setTransactionExecutor(executor)
                    // 在主线程运行
                    .allowMainThreadQueries()
                    .build();
        }
    }

    // 向外提供方法
    public static AppDataBase getAppDataBase(Context context) {
        return Holder.getInstance(context);
    }


    @NonNull
    @Override
    protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration config) {
        return null;
    }

    @NonNull
    @Override
    protected InvalidationTracker createInvalidationTracker() {
        return null;
    }

    @Override
    public void clearAllTables() {

    }


    /**
     * 读取数据库文件（.sql），并执行sql语句
     */
    private static void executeAssetsSQL(SupportSQLiteDatabase db, String schemaName) {
        BufferedReader in = null;
        try {
            in = new BufferedReader(new InputStreamReader(AppContext.getInstance().getAssets()
                    .open(schemaName)));

            //System.out.println("路径:" + Configuration.DB_PATH + "/" + schemaName);
            String line;
            String buffer = "";
            db.beginTransaction();  //手动设置开始事务
            while ((line = in.readLine()) != null) {
                buffer += line;
                if (line.trim().endsWith(";")) {
                    db.execSQL(buffer.replace(";", ""));
                    buffer = "";
                }
            }
            db.setTransactionSuccessful(); //设置事务处理成功，不设置会自动回滚不提交。
        } catch (Exception e) {
            Log.e("shawn_db_error1", e.toString());
        } finally {
            db.endTransaction(); //处理完成
            try {
                if (in != null)
                    in.close();
            } catch (IOException e) {
                Log.e("shawn_db_error2", e.toString());
            }
        }
    }
}
